package reservation.v2;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * Classe trajet : modélisée par une ville de départ, une destination, une date et un type de transport
 * 
 * @author Alexandre Boursier and Jerome Boursier 
 * @version 2011.11.20
 */

public class Trajet {

    /**
     * Ville de départ
     */
    private Ville depart;

    /**
     * Ville d'arrivée
     */
    private Ville arrivee;

    /**
     * Date du trajet 
     */
    private Date date;

    /**
     *  Relation de composition : un trajet donné est effectué par un transport donné
     */
    private Transport transport;

    /**
     * Liste des participants au voyage
     */
    private List<Client> voyageurs;

    /**
     * static qui permet d'incrementer l'ident transport automatiquement
     */
    protected static int ident = 0;

    /**
     * Identifiant du transport
     */
    private int identTrajet;

    /**
     * Créer un trajet selon quatre paramètres
     * 
     * @param start
     *            La ville de départ.
     * @param stop
     *            La ville d'arrivée.
     * @param now
     *            La date à laquelle le trajet aura lieu.
     * @param commute
     *            Le transport utilisé pour le trajet.
     * @param clients
     *            L'ensemble des clients qui ont reservé une place dans ce trajet
     * @throws StartStopException 
     * @throws IOException 
     * @throws NullPointerException 
     * @throws NegativeValueException 
     * @throws NumberFormatException 
     * @throws ParseException 
     */
    public Trajet(Ville start, Ville stop, Date now, Transport commute)
            throws StartStopException, ParseException
            {
        if (start.equals(stop))
            throw new StartStopException(start);
        this.depart = start;
        this.arrivee = stop;
        this.date = now;
        this.transport = commute;
        this.voyageurs = new ArrayList<Client>();
        this.identTrajet = Trajet.ident;
        Trajet.ident++;
            }

    /**
     * Ajouter tous les attributs d'un objet dans une liste
     * 
     * @return la liste des attributs d'un objet
     */
    public List<String> parse()
    {
        List<String> attributes = new ArrayList<String>();
        attributes.add("TRAJET");
        attributes.add(String.valueOf(identTrajet));
        attributes.add(String.valueOf(depart));
        attributes.add(String.valueOf(arrivee));
        attributes.add(this.getDate());
        attributes.add(String.valueOf(transport.getIdentTransport()));
        return attributes;
    }

    /**
     * Créer un trajet existant dans la Base de données (XML)
     * 
     * @param identifiant
     *            Identifiant du trajet
     * @param start
     *            La ville de départ.
     * @param stop
     *            La ville d'arrivée.
     * @param now
     *            La date à laquelle le trajet aura lieu.
     * @param commute
     *            Le transport utilisé pour le trajet.
     * @param clients
     *            L'ensemble des clients qui ont reservé une place dans ce trajet
     * @throws ParseException 
     * @throws StartStopException 
     * @throws NegativeValueException 
     * @throws IOException 
     * @throws NullPointerException 
     * @throws NumberFormatException 
     */
    public Trajet(int identifiant, Ville start, Ville stop, Date now, Transport commute, List<Client> clients)
            throws ParseException 
            {
        this.identTrajet = identifiant;
        if (Trajet.ident <= identifiant)
            Trajet.ident = identifiant + 1;
        this.depart = start;
        this.arrivee = stop;
        this.date = now;
        this.transport = commute;
        this.voyageurs = new ArrayList<Client>(clients);
            }

    /**
     * @return la ville de départ
     */
    public Ville getDepart() {
        return depart;
    }

    /**
     * @param la ville de départ à modifier
     * @throws StartStopException 
     * @throws NegativeValueException 
     * @throws IOException 
     * @throws NullPointerException 
     * @throws NumberFormatException 
     */
    public void setDepart(Ville depart) throws NumberFormatException, NullPointerException, 
    IOException, NegativeValueException, StartStopException {
        if (depart.equals(arrivee))
            throw new StartStopException(depart);
        this.depart = depart;
        SerializeText.alter(this);
    }

    /**
     * @return la ville d'arrivée
     */
    public Ville getArrivee() {
        return arrivee;
    }

    /**
     * @param le ville d'arrivée à modifier
     * @throws StartStopException 
     * @throws NegativeValueException 
     * @throws IOException 
     * @throws NullPointerException 
     * @throws NumberFormatException 
     */
    public void setArrivee(Ville arrivee) throws NumberFormatException, NullPointerException,
    IOException, NegativeValueException, StartStopException {
        if (arrivee.equals(depart))
            throw new StartStopException(depart);
        this.arrivee = arrivee;
        SerializeText.alter(this);
    }

    /**
     * @return la date du trajet
     */
    public String getDate() {
        DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy à HH:mm");
        return dateFormat.format(date);
    }

    /**
     * @param la date du trajet à modifier
     * @throws ParseException 
     * @throws StartStopException 
     * @throws NegativeValueException 
     * @throws IOException 
     * @throws NullPointerException 
     * @throws NumberFormatException 
     */
    public void setDate(Date s) throws ParseException, NumberFormatException, NullPointerException, 
    IOException, NegativeValueException, StartStopException {
        this.date = s;
        SerializeText.alter(this);
    }

    /**
     * Convertir en date
     * 
     * @param s
     *          La chaîne de caractères cible
     * @throws ParseException
     */
    public void toDate(String s) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy à HH:mm");
        this.date = sdf.parse(s);
    }
    
    /**
     * Convertir en date
     * 
     * @param s
     *          La chaîne de caractères cible
     * @throws ParseException
     */
    public static Date toFormatedDate(String s) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy à HH:mm");
        return sdf.parse(s);
    }

    /**
     * @return le transport cible 
     */
    public Transport getTransport() {
        return transport;
    }

    /**
     * @param le transport cible à modifier
     * @throws StartStopException 
     * @throws NegativeValueException 
     * @throws IOException 
     * @throws NullPointerException 
     * @throws NumberFormatException 
     */
    public void setTransport(Transport transport) throws NumberFormatException, NullPointerException,
    IOException, NegativeValueException, StartStopException {
        this.transport = transport;
        SerializeText.alter(this);
    }

    /**
     * @return the identTrajet
     */
    public int getIdentTrajet() {
        return identTrajet;
    }

    /**
     * @return les voyageurs d'un trajet donné
     */
    public List<Client> getVoyageurs() {
        return voyageurs;
    }

    /**
     * Ajouter un client dans la liste des voyageurs
     * @param c
     *          Le client à ajouter
     */
    public void addVoyageur(Client c){
        voyageurs.add(c);
    }

    /**
     * Détermine si un participant existe déjà ou non
     * 
     * @param client
     *            Client cible
     * @return True si le client existe déjà, false sinon
     */
    public boolean exists(Client C) {
        Iterator<Client> iter = voyageurs.iterator();
        while (iter.hasNext()) {
            if (iter.next().getIdentifiant().equals(C.getIdentifiant()))
                return true;
        }
        return false;
    }

    /**
     * 
     * @return le nombre de places restantes
     */
    public int getPlacesRestantes()
    {
        return transport.getCapacite()-voyageurs.size(); 
    }

    /**
     * 
     * @return true si il reste des places, false sinon
     */
    public boolean existPlaces()
    {
        if (getPlacesRestantes() > 0)
            return true;
        else return false;
    }

    /**
     * toString()
     * 
     * @return string contenant la liste des trajets
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("#######################################################\n");
        sb.append("Trajet n°" + identTrajet + "\n");
        sb.append("Départ : " + depart + "\n");
        sb.append("Arrivée : " + arrivee + "\n");
        sb.append("Date : " + this.getDate() + "\n");
        sb.append(transport.toString());

        if (this.getPlacesRestantes() == 0)
            sb.append("Il ne reste plus de places disponibles.\n");
        else
            sb.append("Nombre de places restantes : " + this.getPlacesRestantes() + "\n");

        if (voyageurs.size() > 0)
        {
            sb.append("Liste des voyageurs : \n");
            for (Client c : voyageurs) {
                sb.append("\t");
                sb.append(c.toString());
            }
        }
        else
            sb.append("Pas de voyageur associé au trajet actuellement \n");
        sb.append("#######################################################");
        return sb.toString();
    }

    /**
     * Surcharge de la méthode equals qui sera utilisé dans une liste lorsque 
     * la methode Liste.contains(Objet) est appellée
     * 
     * @param t
     *          L'objet cible
     * @return true si l'identifiant referant de l'objet est le même, false sinon
     */
    @Override
    public boolean equals(Object t)
    {
        Trajet tr = (Trajet)t;
        if(tr.getIdentTrajet() == identTrajet)
            return true;
        return false;
    }

}
